<!DOCTYPE html>
<html>

<head lang="en">
    <meta charset="UTF-8">
    <title>石英钟</title>
    <style>.clock {
        text-align: center;
        padding: 20%
    }
    </style>
</head>

<body>

    <div class="clock">
        <canvas id="clock"></canvas>
    </div>

    <script type="text/javascript">
        var CLOCK = {
            'ctx': '', //canvas Object
            'ctxw': '',//canvas宽度
            'ctxh': '', // canvas高度
            'r': '', //钟表的半径
            hours: [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2], //时刻

            //初始化
            inits: function () {
                var self = this; // 保存this
                self.ctx = document.getElementById('clock').getContext('2d');//方法返回一个用于在画布上绘图的环境
                self.ctxw = self.ctx.canvas.width = 200;//设置width
                self.r = self.ctxw / 2; //获取半径
                self.ctxh = self.ctx.canvas.height = 200;//设置高度

                // 周期性定时器 时间走起来
                setInterval(function () {
                    self.timeRunning();
                }, 1000);
            },

            //时间函数
            timeRunning: function () {
                var self = this,
                    ctx = self.ctx,
                    ctxw = self.ctxw,
                    ctxh = self.ctxh;

                ctx.clearRect(0, 0, ctxw, ctxh); //在给定的矩形内清除指定的像素
                var now = new Date(); //当前时间
                var hour = now.getHours(); //获取时
                var minute = now.getMinutes(); //获取分
                var second = now.getSeconds(); //获取秒

                self.clockDial();
                self.clockHours();

                self.clockwise(hour, minute);
                self.minuteHand(minute, second);
                self.secondHand(second);

                self.circlePoint();

                ctx.restore();//返回之前保存过的路径状态和属性
            },

            //定义表盘
            clockDial: function () {
                var self = this,
                    ctx = self.ctx,
                    circle = {
                        'lineWidth': 10, //线宽
                        'font': '18px Arial', // 文本样式
                        'textAlign': 'center', // 水平居中
                        'textBaseline': 'middle' //垂直居中
                    };

                ctx.beginPath();//定义当前路径
                ctx.lineWidth = circle.lineWidth;
                ctx.strokeStyle = "#999"
                ctx.font = circle.font;
                ctx.textAlign = circle.textAlign;
                ctx.textBaseline = circle.textBaseline;

                //圆的参数
                // arc（x,y,半径,起点，终点，顺时针默认false）
                ctx.arc(self.r, self.r, self.r - 5, 0, 2 * Math.PI, false);
                //绘制已定义的路径
                ctx.stroke();
            },

            //定义时刻、每一个刻度和圆心点
            clockHours: function () {
                var self = this,
                    hours = self.hours,
                    r = self.r,
                    ctx = self.ctx,
                    ctxw = self.ctxw,
                    ctxh = self.ctxh,
                    now = new Date(),
                    yymmdd, //年月日
                    mm; //月份
                /*
                 * hours.forEach(function (val数组元素, idx元素的索引, arr数组本身) {})
                 * 圆上每个点坐标（x,y）:
                 * x = r + Math.sin(2*Math.PI / 360) * (r - offset) // offset 偏移量
                 * y = r + Math.cos(2*Math.PI / 360) * (r - offset)
                 */

                //时刻
                hours.forEach(function (val, idx) {
                    var radian = 2 * Math.PI / 12 * idx;
                    var x = r + Math.cos(radian) * (r - 30);
                    var y = r + Math.sin(radian) * (r - 30);
                    ctx.fillStyle = '#000'; //设置或返回用于填充绘画的颜色、渐变或模式
                    ctx.fillText(val, x, y); //在画布上绘制“被填充的”文本
                });


                /*
                 * 每一个刻度
                 */
                for (var i = 0, len = 60; i < len; i++) {
                    var radian = 2 * Math.PI / len * i;
                    var x = r + Math.cos(radian) * (r - 18);
                    var y = r + Math.sin(radian) * (r - 18);
                    ctx.beginPath();
                    if (i % 5 == 0) { //模除于5等于0
                        ctx.arc(x, y, 2, 0, 2 * Math.PI, false);
                        ctx.fillStyle = '#000'
                    } else {
                        ctx.arc(x, y, 2, 0, 2 * Math.PI, false);
                        ctx.fillStyle = '#999'
                    }
                    ctx.fill();//填充当前绘图（路径
                }

                //定义日期
                ctx.beginPath();
                ctx.lineWidth = 2;
                ctx.strokeRect(ctxw * 0.3, ctxw * 0.62, ctxw * 0.4, 20); //绘制矩形（无填充）
                ctx.beginPath();
                mm = now.getMonth() + 1;
                mm = mm > 10 ? mm : '0' + mm;
                yymmdd = now.getFullYear() + '-' + mm + '-' + now.getDate();
                ctx.font = '14px Arial';//字体样式
                ctx.fillStyle = '#000';
                ctx.fillText(yymmdd, ctxw / 2, ctxw * 2 / 3);
            },

            //定义时针
            clockwise: function (hours, minutes) {
                var self = this,
                    r = self.r,
                    radian,
                    mradian,
                    ctxw = self.ctxw,
                    ctxh = self.ctxh,
                    ctx = self.ctx;
                ctx.save();
                ctx.beginPath();
                radian = 2 * Math.PI / 12 * hours; // 每一个时刻的弧度 * 小时
                mradian = 2 * Math.PI / 12 / 60 * minutes;// 每一分的弧度 * 分数
                ctx.translate(r, r); // translate 改变坐标原点（x,y）.
                ctx.rotate(radian + mradian);
                ctx.lineWidth = 6;
                ctx.strokeStyle = "#000"
                ctx.moveTo(0, 10);//把路径移动到画布中的指定点，不创建线条
                ctx.lineTo(0, -r / 2.5); //添加一个新点，然后在画布中创建从该点到最后指定点的线条

                ctx.stroke();
                ctx.restore();
            },

            //定义分针
            minuteHand: function (minutes, seconds) {
                var self = this,
                    r = self.r,
                    radian,
                    sradian,
                    ctxw = self.ctxw,
                    ctxh = self.ctxh,
                    ctx = self.ctx;
                ctx.save();
                ctx.beginPath();
                radian = 2 * Math.PI / 60 * minutes;
                sradian = 2 * Math.PI / 60 / 60 * seconds;// 每一秒的弧度 * 秒数
                ctx.translate(r, r);
                ctx.rotate(radian + sradian);
                ctx.lineWidth = 4;
                ctx.strokeStyle = "#555"
                ctx.moveTo(0, 15);
                ctx.lineTo(0, -r / 2);
                ctx.stroke();
                ctx.restore();
            },

            //定义秒针
            secondHand: function (seconds) {
                var self = this,
                    r = self.r,
                    radian,
                    sradian,
                    ctxw = self.ctxw,
                    ctxh = self.ctxh,
                    ctx = self.ctx;

                console.log(seconds);
                ctx.save();
                ctx.beginPath();
                radian = 2 * Math.PI / 60 * seconds;
                ctx.translate(r, r);
                ctx.rotate(radian);
                ctx.lineWidth = 3;
                ctx.lineCap = 'round';

                ctx.moveTo(-2, 20);
                ctx.lineTo(2, 20);
                ctx.lineTo(1, -r + 18);
                ctx.lineTo(-1, -r + 18);
                ctx.fillStyle = '#c14543';
                ctx.fill();

                ctx.restore();
            },

            circlePoint: function () {
                var self = this,
                    r = self.r,
                    ctx = self.ctx;
                //圆心
                ctx.beginPath();
                ctx.arc(r, r, 2, 0, 2 * Math.PI, false);
                ctx.fillStyle = '#FFFFFF';
                ctx.fill();
            }
        };

        CLOCK.inits();

    </script>

</body>

</html>